﻿using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Text;
using Pixysoft.Reflection;
using System.Web.UI.WebControls;
using System.Collections.Generic;
using System.Web.UI.HtmlControls;
using System.ComponentModel;

namespace Pixysoft.Framework.Jsons.WebControls
{
    [
    ValidationPropertyAttribute("Text"),
    Designer(typeof(PixysoftAjaxDesigner)),
    DescriptionAttribute("Pixysoft Ajax Framework Library.")
    ]
    public class PixysoftAjax : WebControl, ICallbackEventHandler
    {
        private List<string> syslist = null;

        private const string default_inner_arg = "inner_arg";

        private const string default_callback = "Callback";

        private string functionResult = null;

        public PixysoftAjax()
        {
            this.syslist = SystemMethodList();
        }

        protected override void CreateChildControls()
        {
            ClientScriptManager cs = Page.ClientScript;

            Type methodType = this.Page.GetType();

            List<string> mlist = MethodReflector.GetMethods(methodType, typeof(AjaxEnabledAttribute));

            foreach (string jsMethod in mlist)
            {
                if (syslist.Contains(jsMethod))
                    continue;

                bool hasreturn = MethodReflector.HasReturn(methodType, jsMethod);

                String callbackScript1 = GetJsScript(jsMethod,
                    GetCallbackReference(cs, jsMethod, hasreturn),
                    MethodReflector.GetArgs(methodType, jsMethod).ToArray());

                cs.RegisterClientScriptBlock(this.GetType(), Guid.NewGuid().ToString(),
                        callbackScript1, true);
            }

            base.CreateChildControls();
        }

        public string GetCallbackResult()
        {
            return functionResult;
        }

        public void RaiseCallbackEvent(string eventArgument)
        {
            functionResult = null;

            string jsMethodname = GetJsMethodName(eventArgument);

            if (string.IsNullOrEmpty(jsMethodname))
                return;

            if (!MethodReflector.GetMethods(this.Page.GetType()).Contains(jsMethodname))
                return;

            if (MethodReflector.HasReturn(this.Page.GetType(), jsMethodname))
            {
                object rvalue = MethodReflector.GetValue(this.Page.GetType(), this.Page, jsMethodname, GetJsParameters(eventArgument));

                if (rvalue == null)
                    return;

                functionResult = rvalue.ToString();
            }
            else
            {
                if (!MethodReflector.SetValue(this.Page, jsMethodname,
                     GetJsParameters(eventArgument)))
                {
                    throw new Exception("cannot set value for the method");
                }
            }

        }

        private string GetJsMethodName(string eventArgument)
        {
            if (string.IsNullOrEmpty(eventArgument))
                return eventArgument;

            return eventArgument.Split(';')[0].Trim();

        }

        private string[] GetJsParameters(string eventArgument)
        {
            if (eventArgument == null)
                return null;

            string[] args = eventArgument.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);


            if (args.Length < 2)
                return null;

            List<string> list = new List<string>();

            for (int i = 1; i < args.Length; i++)
            {
                list.Add(args[i]);
            }

            return list.ToArray();
        }

        private string GetCallbackReference(ClientScriptManager cs, string jsMethodname, bool hasreturn)
        {
            string cbReference = null;

            if (hasreturn)
            {
                cbReference = cs.GetCallbackEventReference(
                 this,
                  default_inner_arg,
                  jsMethodname + default_callback, null);
            }
            else
            {
                cbReference = cs.GetCallbackEventReference(
                   this,
                   default_inner_arg,
                   jsMethodname + default_callback,
                   GetDefaultCallbackFunction(jsMethodname));
            }

            return cbReference;
        }

        private string GetDefaultCallbackFunction(string jsMethodName)
        {
            StringBuilder builder = new StringBuilder();

            builder.AppendFormat("function {0}{1}({2})", jsMethodName, default_callback, default_inner_arg);
            builder.Append("{");
            //builder.AppendFormat("return {0};", default_inner_arg);
            builder.Append("}");

            return builder.ToString();
        }

        private string GetJsScript(string method, string callbackreference, params string[] args)
        {
            StringBuilder builder = new StringBuilder();

            builder.AppendFormat("function {0}(", method);

            if (args != null && args.Length > 0)
            {
                foreach (string arg in args)
                {
                    builder.Append(arg + ",");
                }

                builder.Remove(builder.Length - 1, 1);
            }

            builder.Append(")");

            builder.Append("{");

            builder.AppendFormat("var {0}='{1};'{2};", default_inner_arg, method, ArrayToJsString(args));

            builder.AppendFormat("{0};", callbackreference);

            builder.Append("}");

            return builder.ToString();
        }

        private string ArrayToJsString(params string[] args)
        {
            if (args == null)
                return "";

            if (args.Length == 0)
                return "";

            StringBuilder builder = new StringBuilder();
            foreach (string arg in args)
            {
                builder.Append("+" + arg + "+';'");
            }
            if (builder.Length > 0)
                builder.Remove(builder.Length - 4, 4);

            return builder.ToString();
        }

        private List<string> SystemMethodList()
        {
            List<string> list = new List<string>();
            list.Add("GetTypeHashCode");
            list.Add("ProcessRequest");
            list.Add("set_TraceEnabled");
            list.Add("get_TraceEnabled");
            list.Add("set_TraceModeValue");
            list.Add("get_TraceModeValue");
            list.Add("get_EnableViewStateMac");
            list.Add("set_EnableViewStateMac");
            list.Add("get_SmartNavigation");
            list.Add("set_SmartNavigation");
            list.Add("get_IsAsync");
            list.Add("add_LoadComplete");
            list.Add("remove_LoadComplete");
            list.Add("add_PreInit");
            list.Add("remove_PreInit");
            list.Add("add_PreLoad");
            list.Add("remove_PreLoad");
            list.Add("add_PreRenderComplete");
            list.Add("remove_PreRenderComplete");
            list.Add("add_InitComplete");
            list.Add("remove_InitComplete");
            list.Add("RegisterRequiresViewStateEncryption");
            list.Add("add_SaveStateComplete");
            list.Add("remove_SaveStateComplete");
            list.Add("get_Form");
            list.Add("RegisterViewStateHandler");
            list.Add("ExecuteRegisteredAsyncTasks");
            list.Add("RegisterAsyncTask");
            list.Add("AddOnPreRenderCompleteAsync");
            list.Add("AddOnPreRenderCompleteAsync");
            list.Add("Validate");
            list.Add("Validate");
            list.Add("GetValidators");
            list.Add("VerifyRenderingInServerForm");
            list.Add("get_PageAdapter");
            list.Add("get_Items");
            list.Add("GetDataItem");
            list.Add("SetFocus");
            list.Add("SetFocus");
            list.Add("GetPostBackEventReference");
            list.Add("GetPostBackEventReference");
            list.Add("GetPostBackClientEvent");
            list.Add("GetPostBackClientHyperlink");
            list.Add("IsClientScriptBlockRegistered");
            list.Add("IsStartupScriptRegistered");
            list.Add("RegisterArrayDeclaration");
            list.Add("RegisterHiddenField");
            list.Add("RegisterClientScriptBlock");
            list.Add("RegisterStartupScript");
            list.Add("RegisterOnSubmitStatement");
            list.Add("RegisterRequiresControlState");
            list.Add("RequiresControlState");
            list.Add("UnregisterRequiresControlState");
            list.Add("RegisterRequiresPostBack");
            list.Add("RegisterRequiresRaiseEvent");
            list.Add("get_IsPostBackEventControlRegistered");
            list.Add("get_IsValid");
            list.Add("get_Validators");
            list.Add("get_PreviousPage");
            list.Add("MapPath");
            list.Add("set_Buffer");
            list.Add("get_Buffer");
            list.Add("set_ContentType");
            list.Add("get_ContentType");
            list.Add("set_CodePage");
            list.Add("get_CodePage");
            list.Add("set_ResponseEncoding");
            list.Add("get_ResponseEncoding");
            list.Add("set_Culture");
            list.Add("get_Culture");
            list.Add("set_LCID");
            list.Add("get_LCID");
            list.Add("set_UICulture");
            list.Add("get_UICulture");
            list.Add("set_AsyncTimeout");
            list.Add("get_AsyncTimeout");
            list.Add("get_Application");
            list.Add("get_ClientScript");
            list.Add("get_ClientTarget");
            list.Add("set_ClientTarget");
            list.Add("get_ClientQueryString");
            list.Add("get_ErrorPage");
            list.Add("set_ErrorPage");
            list.Add("get_IsCallback");
            list.Add("get_IsReusable");
            list.Add("get_AutoPostBackControl");
            list.Add("set_AutoPostBackControl");
            list.Add("get_Header");
            list.Add("get_IdSeparator");
            list.Add("get_MaintainScrollPositionOnPostBack");
            list.Add("set_MaintainScrollPositionOnPostBack");
            list.Add("get_Master");
            list.Add("get_MasterPageFile");
            list.Add("set_MasterPageFile");
            list.Add("get_MaxPageStateFieldLength");
            list.Add("set_MaxPageStateFieldLength");
            list.Add("get_Trace");
            list.Add("get_Request");
            list.Add("get_Response");
            list.Add("get_Server");
            list.Add("get_Cache");
            list.Add("get_Session");
            list.Add("get_Title");
            list.Add("set_Title");
            list.Add("get_Theme");
            list.Add("set_Theme");
            list.Add("get_StyleSheetTheme");
            list.Add("set_StyleSheetTheme");
            list.Add("get_User");
            list.Add("FindControl");
            list.Add("get_IsCrossPagePostBack");
            list.Add("get_IsPostBack");
            list.Add("get_EnableEventValidation");
            list.Add("set_EnableEventValidation");
            list.Add("get_EnableViewState");
            list.Add("set_EnableViewState");
            list.Add("get_ViewStateEncryptionMode");
            list.Add("set_ViewStateEncryptionMode");
            list.Add("get_ViewStateUserKey");
            list.Add("set_ViewStateUserKey");
            list.Add("get_ID");
            list.Add("set_ID");
            list.Add("get_Visible");
            list.Add("set_Visible");
            list.Add("DesignerInitialize");
            list.Add("add_CommitTransaction");
            list.Add("remove_CommitTransaction");
            list.Add("get_EnableTheming");
            list.Add("set_EnableTheming");
            list.Add("add_AbortTransaction");
            list.Add("remove_AbortTransaction");
            list.Add("add_Error");
            list.Add("remove_Error");
            list.Add("ReadStringResource");
            list.Add("get_AppRelativeVirtualPath");
            list.Add("set_AppRelativeVirtualPath");
            list.Add("TestDeviceFilter");
            list.Add("LoadControl");
            list.Add("LoadControl");
            list.Add("LoadTemplate");
            list.Add("ParseControl");
            list.Add("ParseControl");
            list.Add("RenderControl");
            list.Add("Dispose");
            list.Add("get_Controls");
            list.Add("ResolveUrl");
            list.Add("ResolveClientUrl");
            list.Add("HasControls");
            list.Add("SetRenderMethodDelegate");
            list.Add("get_ClientID");
            list.Add("add_Disposed");
            list.Add("remove_Disposed");
            list.Add("get_SkinID");
            list.Add("set_SkinID");
            list.Add("get_NamingContainer");
            list.Add("get_BindingContainer");
            list.Add("get_Page");
            list.Add("set_Page");
            list.Add("get_TemplateControl");
            list.Add("set_TemplateControl");
            list.Add("get_Parent");
            list.Add("get_TemplateSourceDirectory");
            list.Add("get_AppRelativeTemplateSourceDirectory");
            list.Add("set_AppRelativeTemplateSourceDirectory");
            list.Add("get_Site");
            list.Add("set_Site");
            list.Add("get_UniqueID");
            list.Add("add_DataBinding");
            list.Add("remove_DataBinding");
            list.Add("add_Init");
            list.Add("remove_Init");
            list.Add("add_Load");
            list.Add("remove_Load");
            list.Add("add_PreRender");
            list.Add("remove_PreRender");
            list.Add("add_Unload");
            list.Add("remove_Unload");
            list.Add("ApplyStyleSheetSkin");
            list.Add("DataBind");
            list.Add("Focus");
            list.Add("ToString");
            list.Add("Equals");
            list.Add("GetHashCode");
            list.Add("GetType");
            return list;
        }
    }
}